/*
 * MixerMission.cpp
 *
 *  Created on: Nov 27, 2013
 *      Author: wyf
 */

#include "stdio.h"
#include "MixerMission.h"
#include "PacketQueue.h"
#include "ct_log_macro.h"

#include <string>
#include <sstream>

void WriteRawPcmToFile(const void *data, int len)
{
	FILE* file = fopen("./PcmData.pcm", "ab+");
	fwrite(data, 1, len, file);
	fclose(file);
	file = NULL;	
}

void WriteIsacToFile(const void *data, int len)
{
	FILE* file = fopen("./IsacData.isac", "ab+");
	fwrite(data, 1, len, file);
	fclose(file);
	file = NULL;	
}

MixerMission::MixerMission(DWORD roomid, DWORD recid, DWORD sttime, DWORD endtime, const char *path) :
	_MissionID(roomid), sttime_(sttime), endtime_(endtime), recid_(recid)
{
	//_TDecoding = NULL;

	user_id_ = 0;
	channel_id_ = 0xFFFF;

	m_voe = NULL;
	base = NULL;
	codec = NULL;
	netw = NULL;
	mixer = NULL;
	rtcp = NULL;
	media = NULL;
	apm = NULL;
	bzero(path_, sizeof(path_));
	strncpy(path_, path, 127);
}

MixerMission::~MixerMission()
{
	// TODO Auto-generated destructor stub
//	ThreadDecoding::Destroy(_TDecoding);
	this->clear();
}

DWORD MixerMission::Create(MixerMission *&mission, DWORD roomid, DWORD recid, DWORD sttime, DWORD endtime, const char *path)
{
	mission = new MixerMission(roomid, recid, sttime, endtime, path);
	if (mission == NULL) {
		return -1;
	}
	mission->init();
	return 0;
}

void MixerMission::Destroy(MixerMission*& mission)
{
	if (mission) 
	{       
		delete mission;
		mission = NULL;
	}
}

void MixerMission::init()
{
	CT_TRACE(__PRETTY_FUNCTION__);
	m_voe = VoiceEngine::Create();
	//m_voe->SetTraceFilter(kTraceWarning | kTraceError);
	//m_voe->SetTraceFile("/log/webrtc.log");
	m_voe->SetTraceFilter(kTraceNone);
	base = VoEBase::GetInterface(m_voe);
	base->Init();
	codec = VoECodec::GetInterface(m_voe);
	netw = VoENetwork::GetInterface(m_voe);
	mixer = VoEMixer::GetInterface(m_voe);
	rtcp = VoERTP_RTCP::GetInterface(m_voe);
	media = VoEExternalMedia::GetInterface(m_voe);
	apm = VoEAudioProcessing::GetInterface(m_voe);

	int ret = media->SetExternalRecordingStatus(true);
	if (ret == 0) {
		CT_INFO("%s. SetExternalRecordingStatus ok", __PRETTY_FUNCTION__);
	}
	else {
		CT_WARN("%s. SetExternalRecordingStatus failed", __PRETTY_FUNCTION__);
	}

	//apm = VoEAudioProcessing::GetInterface(m_voe);

	mixer->RegisterStreamout(*this);
/*	if (0 == ThreadDecoding::Create(_TDecoding, this)) {
		_TDecoding->start();
	}
*/
/*
	std::string filename;
	if (true == createFileName(recid_, filename)) {
		Zebra::logger->info("----[xuhui]create file name(%s)", filename.c_str());
		if (mp3encoder_.open(filename.c_str()) < 0) {
			Zebra::logger->error("----[xuhui]open mp3 file failed");
		}
	}
	else {
		CT_WARN("----[xuhui]create file name failed");
	}
*/
	Zebra::logger->debug("----[xuhui]MixerMission::inited");
}

bool MixerMission::createFileName(const DWORD &recid, std::string &filename)
{
	int len = strlen(path_);
	if (len == 0) {
		return false;
	}

	time_t ticks;
	struct tm *t;
	ticks = time(NULL);
	t = localtime(&ticks);
	char date[128] = { 0 };
	strftime(date, 127, "(%Y-%m-%d-%H-%M-%S).mp3", t);

	std::stringstream filenamess;
	if (path_[len -1] == '/') {
		filenamess<<path_<<recid<<".mp3";
	}
	else {
		filenamess<<path_<<"/"<<recid<<".mp3";
	}

	filename = filenamess.str();
	return true;
}

void MixerMission::updateMissionTime(DWORD stTime, DWORD endTime)
{
	if (stTime != 0)
	{
		sttime_ = stTime;
	}

	if (endTime != 0)
	{
		endtime_ = endTime;
	}
}

bool MixerMission::isTimeOut(DWORD curtime)
{
	if (curtime >= endtime_ + 60*3) {
		Zebra::logger->info("----[xuhui]isTimeOut curtime(%u), endtime(%u), offset(%u)", curtime, endtime_, curtime - endtime_);
		return true;
	}

	return false;
}

void MixerMission::clear()
{
	Zebra::logger->debug("----[xuhui]MixerMission::clear");

	mixer->DeRegisterStreamout();
	if (mixer)
		mixer->Release();

	if (base) {
		// base->Terminate();
		base->Release();
	}

	if (codec)
		codec->Release();

	if (netw)
		netw->Release();
	if (rtcp)
		rtcp->Release();
	if (media)
		media->Release();
	if (apm)
		apm->Release();

	VoiceEngine::Delete(m_voe);

	_Queue.freePool();
//	mp3encoder_.close();
}

void MixerMission::onRtpPacket(UDPPacket* pack)
{
	if (pack == NULL) {
		Zebra::logger->debug("----[xuhui]pack is NULL");
		return;
	}

	_Queue.push(pack);
	/* static DWORD s_count = 0;
	   if (s_count >= 10) {
	   Zebra::logger->debug("----[xuhui]recv rtp packet");
	   s_count = 0;
	   }
	   else {
	   s_count++;
	   } */
}

bool MixerMission::process()
{
	UDPPacket* pack = _Queue.pop();

	if (pack == NULL) {
		return false;
	}

	if (pack->_type == 0) {
		AudioCmd::stUDPPkgHead *rev = reinterpret_cast<AudioCmd::stUDPPkgHead *>(pack->_buf);
		if (rev->type_ == AudioCmd::CMD_AUDIO_FORWARD) {
			AudioCmd::stUDPForwardRoom *oldCmd = reinterpret_cast<AudioCmd::stUDPForwardRoom *>(rev);
			TM_CIT it = _channels.find(oldCmd->user_id_);
			if (it != _channels.end()) {
				netw->ReceivedRTPPacket(it->second, oldCmd->data, oldCmd->data_size_);
			}
		}
		else if (rev->type_ == AudioCmd::CMD_AUDIO_FORWARD_NEW) {
			AudioCmd::stUDPForwardRoomNew *newCmd = reinterpret_cast<AudioCmd::stUDPForwardRoomNew *>(rev);
			TM_CIT it = _channels.find(newCmd->user_from_);
			if (it != _channels.end()) {
				netw->ReceivedRTPPacket(it->second, newCmd->data, newCmd->data_size_);
			}
		}
		else if (rev->type_ == AudioCmd::CMD_AUDIO_FORWARD_NEW_NEW) {
			AudioCmd::stUDPForwardRoomNewNew *newCmd = reinterpret_cast<AudioCmd::stUDPForwardRoomNewNew *>(rev);
			TM_CIT it = _channels.find(newCmd->user_from_);
			if (it != _channels.end()) {
				netw->ReceivedRTPPacket(it->second, newCmd->data, newCmd->data_size_);
			}
		}
		else {
			Zebra::logger->debug("----[xuhui]error audio packet");
		}

	} 
	else if (pack->_type == 2) {
		//create chan
		DWORD *userid = reinterpret_cast<DWORD *>(pack->_buf);
		Zebra::logger->debug("----[xuhui]creating new channel, userid(%u)", *userid);
		TM_CIT it = _channels.find(*userid);
		if (it == _channels.end()) {
			int channelID = base->CreateChannel();
			if (channelID < 0) {
				Zebra::logger->debug("----[xuhui]create new channel failed");
				delete pack;
				return false;
			}


			int ret = netw->RegisterExternalTransport(channelID, *this);
			if (ret < 0) {
				Zebra::logger->debug("----[xuhui]RegisterExternalTransport channel(%u), userid(%u) to failed", channelID, *userid);
				delete pack;
				return false;
			}
			ret = rtcp->SetRTCPStatus(channelID, false);
			if (ret < 0) {
				Zebra::logger->debug("----[xuhui]SetRTCPStatus channel(%u), userid(%u) to failed", channelID, *userid);
				delete pack;
				return false;
			}


			Zebra::logger->debug("----[xuhui]SetRTCPStatus channel(%u), userid(%u) to success(default webrtc payload)", channelID, *userid);

			Zebra::logger->debug("----[xuhui]created new channel(%u), userid(%u)", channelID, *userid);
			CodecInst code;
			int num = codec->NumOfCodecs();
			int i = 0;
			for (; i < num; i++) {
				if (codec->GetCodec(i, code) != -1) {
					if (strncmp(code.plname, "ISAC", 4) == 0 && code.pltype == 104) {
						break;
					}
				}
			}

			if (i >= num) {	
				Zebra::logger->error("----[xuhui]can't find isac");
				codec->GetCodec(0, code);
				codec->SetSendCodec(channelID, code);
			}
			else {
				Zebra::logger->debug("----[xuhui]isac is ok 104");
				codec->SetSendCodec(channelID, code);
			}

			base->StartSend(channelID);
			mixer->InsertIntoMixer(channelID);
			apm->SetRxAgcStatus(channelID, true, kAgcDefault);

			_channels.insert(TM_VT(*userid, channelID));

			if (user_id_ == 0) {
				user_id_ = *userid;
				Zebra::logger->debug("----[xuhui]new userid(%u)", *userid);
			}
			if (channel_id_ == 0xFFFF) {
				channel_id_ = channelID;
				Zebra::logger->debug("----[xuhui]new channelid(%u)", channelID);
			}
		}
	} else if (pack->_type == 3) {
		//leave
		DWORD *userid = reinterpret_cast<DWORD *>(pack->_buf);

		TM_IT it = _channels.find(*userid);
		if (it != _channels.end()) {

			mixer->DeleteFromMixer(it->second);
			netw->DeRegisterExternalTransport(it->second);
			base->StopSend(it->second);
			base->DeleteChannel(it->second);
			Zebra::logger->error("----[xuhui]user(%u) delete channel(%u) from room(%u)", *userid, it->second, _MissionID);

			_channels.erase(it);
			if (*userid == user_id_) {
				if (_channels.size() > 0) {
					TM_IT tmp = _channels.begin();
					user_id_ = tmp->first;
					channel_id_ = tmp->second;
				} else {
					user_id_ = 0;
					channel_id_ = 0xFFFF;
				}
			}

			Zebra::logger->error("----[xuhui]new userid(%u), new channel(%u)", user_id_, channel_id_);	
		}
	}

	delete pack;
	return true;
}

void MixerMission::getAudioPacket(t_BufferCmdQueue &to)
{
	mutex_audio_packet_.lock();
	to.put(queue_audio_packet_.rd_buf(), queue_audio_packet_.rd_size());
	// Zebra::logger->debug("----[xuhui]getAudioPacket channel(%u), len(%u)", _MissionID, queue_audio_packet_.rd_size());
	queue_audio_packet_.reset();
	mutex_audio_packet_.unlock();
}

int MixerMission::onRawPcm(const void *data, int len, int samples_per_sec, int num_channels)
{       
	int res = 0;
	if (base) {
		res = base->DeliverPCMData(data, len/(2*num_channels), 2*num_channels, num_channels, samples_per_sec);
		//WriteRawPcmToFile(data, len);
		/*static DWORD s_count = 0;
		  if (s_count >= 10) {
		  s_count = 0;
		  Zebra::logger->debug("----[xuhui]onRawPcm roomid(%u), samples_per_sec(%u), num_channels(%u), monosecsamples(%u)", _MissionID, samples_per_sec, num_channels, len/(2*num_channels));
		  }
		  else {
		  s_count++;
		  }*/
	}
	else {
		Zebra::logger->debug("----[xuhui]base is null");
	}

	//WriteRawPcmToFile(data, len);
	return res;
}

int MixerMission::SendPacket(int channel, const void *data, int len)
{
	return 0;
}

void MixerMission::addMute(const uint8_t *data, const DWORD &len)
{
	if (true == _channels.empty()) {
		//mp3encoder_.encode(data, len);
	}
}

